/** * Copyright Red Hat, Inc, and individual contributors. * <p> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.feedhenry.sdk.api; import android.os.Looper; import android.support.test.runner.AndroidJUnit4; import com.feedhenry.sdk.FH; import com.feedhenry.sdk.FHAct; import com.feedhenry.sdk.FHActCallback; import com.feedhenry.sdk.FHResponse; import com.feedhenry.sdk.utils.DataManager; import com.squareup.okhttp.mockwebserver.MockResponse; import com.squareup.okhttp.mockwebserver.MockWebServer; import com.squareup.okhttp.mockwebserver.RecordedRequest; import org.json.fh.JSONException; import org.json.fh.JSONObject; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import cz.msebera.android.httpclient.Header; import cz.msebera.android.httpclient.message.BasicHeader; import static android.support.test.InstrumentationRegistry.getContext; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertTrue; @RunWith(AndroidJUnit4.class) public class FHSDKTest { private JSONObject resJson = null; private MockWebServer mockWebServer = null; @Before public void setUp() throws Exception { mockWebServer = new MockWebServer(); mockWebServer.play(9000); FH.init(getContext(), null); // this will load fhconfig.local.properties file FH.setLogLevel(FH.LOG_LEVEL_VERBOSE); DataManager.getInstance().save(FHAuthSession.SESSION_TOKEN_KEY, "testsessiontoken"); } @After public void tearDown() throws Exception { shutdownServer(); FH.stop(); } @Test public void testFHActASync() throws Exception { actTest(true); } @Test public void testFhActSync() throws Exception { actTest(false); } public void actTest(boolean async) throws Exception { String cloudHost = FH.getCloudHost(); System.out.println("cloud host is " + cloudHost); // the fhconfig.local.properties file exists, use the host value from that // file as the cloud host assertEquals("http://localhost:9000", cloudHost); // mock response for act call MockResponse actSuccessResponse = new MockResponse(); actSuccessResponse.addHeader("Content-Type", "application/json"); actSuccessResponse.setBody("{'status':'ok', 'type': 'act'}"); mockWebServer.enqueue(actSuccessResponse); FHAct actCall = FH.buildActRequest("test", new JSONObject()); FHActCallback callback = new FHActCallback() { @Override public void success(FHResponse pResponse) { resJson = pResponse.getJson(); } @Override public void fail(FHResponse pResponse) { resJson = null; } }; if (async) { runAsyncRequest(actCall, callback); } else { actCall.execute(callback); } assertEquals(resJson.getString("type"), "act"); // verify request object RecordedRequest request = mockWebServer.takeRequest(); assertEquals("POST", request.getMethod().toUpperCase()); assertEquals("/cloud/test", request.getPath()); String requestBody = new String(request.getBody().readUtf8()); JSONObject requestJson = new JSONObject(requestBody); assertTrue(requestJson.has("__fh")); JSONObject fhParams = requestJson.getJSONObject("__fh"); String deviceId = fhParams.optString("cuid", null); assertEquals(getDeviceId(), deviceId); } @Test public void testCloudGetSync() throws Exception { enqueueCloudResponse(); JSONObject p = new JSONObject(); p.put("test", "true"); makeCloudRequest("GET", null, p, false); verifyCloudRequest("/v1/cloud/test?test=true", "GET", null, null); } @Test public void testCloudGetAsync() throws Exception { enqueueCloudResponse(); JSONObject p = new JSONObject(); p.put("test", "true"); makeCloudRequest("GET", null, p, true); verifyCloudRequest("/v1/cloud/test?test=true", "GET", null, null); } @Test public void testCloudDeleteSync() throws Exception { enqueueCloudResponse(); JSONObject p = new JSONObject(); p.put("test", "true"); makeCloudRequest("DELETE", null, p, false); verifyCloudRequest("/v1/cloud/test?test=true", "DELETE", null, null); } @Test public void testCloudDeleteAsync() throws Exception { enqueueCloudResponse(); JSONObject p = new JSONObject(); p.put("test", "true"); makeCloudRequest("DELETE", null, p, true); verifyCloudRequest("/v1/cloud/test?test=true", "DELETE", null, null); } @Test public void testCloudPostSync() throws Exception { enqueueCloudResponse(); JSONObject p = new JSONObject(); p.put("test", "true"); Header[] headers = new Header[1]; headers[0] = new BasicHeader("testHeader", "testValue"); makeCloudRequest("POST", headers, p, false); verifyCloudRequest("/v1/cloud/test", "POST", headers, p); } @Test public void testCloudPostASync() throws Exception { enqueueCloudResponse(); JSONObject p = new JSONObject(); p.put("test", "true"); Header[] headers = new Header[1]; headers[0] = new BasicHeader("testHeader", "testValue"); makeCloudRequest("POST", headers, p, true); verifyCloudRequest("/v1/cloud/test", "POST", headers, p); } @Test public void testCloudPutSync() throws Exception { enqueueCloudResponse(); JSONObject p = new JSONObject(); p.put("test", "true"); Header[] headers = new Header[1]; headers[0] = new BasicHeader("testHeader", "testValue"); makeCloudRequest("PUT", headers, p, false); verifyCloudRequest("/v1/cloud/test", "PUT", headers, p); } @Test public void testCloudPutASync() throws Exception { enqueueCloudResponse(); JSONObject p = new JSONObject(); p.put("test", "true"); Header[] headers = new Header[1]; headers[0] = new BasicHeader("testHeader", "testValue"); makeCloudRequest("PUT", headers, p, true); verifyCloudRequest("/v1/cloud/test", "PUT", headers, p); } private void shutdownServer() throws Exception { mockWebServer.shutdown(); // Git a little bit time to allow mockWebServer shutdown properly Thread.sleep(100); } private void enqueueCloudResponse() throws Exception { MockResponse cloudSuccessResponse = new MockResponse(); cloudSuccessResponse.addHeader("Content-Type", "application/json"); cloudSuccessResponse.setBody("{'status':'ok', 'type': 'cloud'}"); mockWebServer.enqueue(cloudSuccessResponse); } private void makeCloudRequest(String method, Header[] headers, JSONObject params, boolean pAsync) throws JSONException, Exception { FHCloudRequest cloudRequest = FH.buildCloudRequest("/v1/cloud/test", method, headers, params); FHActCallback callback = new FHActCallback() { @Override public void success(FHResponse pResponse) { resJson = pResponse.getJson(); } @Override public void fail(FHResponse pResponse) { resJson = null; } }; if (pAsync) { runAsyncRequest(cloudRequest, callback); } else { cloudRequest.execute(callback); } assertNotNull(resJson); assertEquals("cloud", resJson.getString("type")); } private void verifyCloudRequest(String path, String method, Header[] headers, JSONObject params) throws Exception { RecordedRequest request = mockWebServer.takeRequest(); assertEquals(method.toLowerCase(), request.getMethod().toLowerCase()); String cuidHeader = request.getHeader("x-fh-cuid"); assertEquals(getDeviceId(), cuidHeader); if (null != headers) { for (int i = 0; i < headers.length; i++) { String requestHeaderValue = request.getHeader(headers[i].getName()); assertEquals(requestHeaderValue, headers[i].getValue()); } } if (null != params) { String requestBody = new String(request.getBody().readUtf8()); assertEquals(requestBody.toString(), params.toString()); } } private String getDeviceId() { return android.provider.Settings.Secure.getString(getContext() .getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); } private void runAsyncRequest(final FHAct pRequest, final FHActCallback pCallback) throws Exception { // The AsyncHttpClient uses Looper & Handlers to implement async http calls. // It requires the calling thread to have a looper attached to it. // When requests are made from the main UI thread, it will work find as the // main UI thread contains a main Looper. // However, if the app creates another Thread which will be used to invoke // the call, it should use the sync mode or attach the looper to the thread // as demoed below. // The main thread that runs the tests doesn't work with Handlers either. Thread testThread = new Thread() { @Override public void run() { try { Looper.prepare(); pRequest.executeAsync(new FHActCallback() { @Override public void success(FHResponse pResponse) { System.out.println("Got response " + pResponse.getRawResponse()); pCallback.success(pResponse); Looper.myLooper().quit(); } @Override public void fail(FHResponse pResponse) { System.out.println("Got error response : " + pResponse.getRawResponse()); pCallback.fail(pResponse); Looper.myLooper().quit(); } }); Looper.loop(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; testThread.start(); testThread.join(); } }